home *** CD-ROM | disk | FTP | other *** search
-
- #ifdef MSDOS
- /* memory allocation routines
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Adapted from alloc routine in K&R; memory statistics and interrupt
- * protection added for use with net package. Must be used in place of
- * standard Turbo-C library routines because the latter check for stack/heap
- * collisions. This causes erroneous failures because process stacks are
- * allocated off the heap.
- *
- * Mods by G1EMM , PA0GRI, KO4KS
- */
-
- #define __dj_include_stdlib_h_
- #include "global.h"
- #define FP_OFF( fp )( (unsigned )( fp ))
- #include "proc.h"
- #include "socket.h"
- #include "commands.h"
- #include <dpmi.h>
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: alloc.c,v 1.20 1997/07/31 00:44:20 root Exp root $";
- #endif
-
- static unsigned long Memfail = 0; /* Count of allocation failures */
- static unsigned long Allocs = 0; /* Total allocations */
- static unsigned long Frees = 0; /* Total frees */
- static unsigned long Invalid = 0; /* Total calls to free with garbage arg */
- static unsigned long Yellows = 0; /* Yellow alert garbage collections */
- static unsigned long Reds = 0; /* Red alert garbage collections */
- static int Memwait; /* Number of tasks waiting for memory */
- static unsigned long Availmem = 0; /* Heap memory, ABLKSIZE units */
- static unsigned long Morecores = 0;
- static int Memdebug = 0; /* 0 = normal, 1 = call logstat() */
- static char freewarn[] ="free: WARNING! %s (%08x) pc = %04x:%04x proc %s%c";
- static char freewarn1[] = "invalid pointer";
- static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu";
- #ifdef Kelvdebug
- static unsigned long Overuse = 0; /* Total calls to free with overused arg */
- static char freewarn2[] = "overused buffer";
- static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu, overused %lu";
- #else
- static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu";
- #endif
- static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
- static char ThreshStr[] = "threshold %lu";
-
- static unsigned long Sizes[16] = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
- 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L };
-
- static int logstat (void);
-
- static unsigned long availmem (void);
- int domemstat (int argc,char *argv[],void *p);
- static int dofreelist (int argc,char *argv[],void *p);
- static int dothresh (int argc,char *argv[],void *p);
- static int dosizes (int argc,char *argv[],void *p);
- static int domemdebug (int argc,char *argv[],void *p);
- static int dogcollect (int argc,char *argv[],void *p);
-
- static struct cmds Memcmds[] = {
- { "debug", domemdebug, 0, 0, NULLCHAR },
- { "freelist", dofreelist, 0, 0, NULLCHAR },
- { "gcollect", dogcollect, 0, 0, NULLCHAR },
- { "sizes", dosizes, 0, 0, NULLCHAR },
- { "status", domemstat, 0, 0, NULLCHAR },
- { "thresh", dothresh, 0, 0, NULLCHAR },
- { NULLCHAR, NULL, 0, 0, NULLCHAR }
- };
-
-
- struct header {
- struct header *ptr;
- unsigned long size;
- };
-
- typedef struct header HEADER;
- #define NULLHDR (HEADER *)NULL
-
- #define ABLKSIZE (sizeof (HEADER))
-
- static HEADER *morecore (unsigned nu);
-
- static HEADER Base;
- static HEADER *Allocp = NULLHDR;
- static unsigned long Heapsize = 0;
-
- #ifdef Kelvdebug
- #define MARKER 0x766c654bL /* Kelv in reverse */
- #endif
-
-
- static void *_malloc (unsigned nb);
-
- #if 0
- /* Allocate block of 'nb' bytes */
- void *
- malloc(nb)
- unsigned nb;
- {
- void * retval;
-
- retval = _malloc (nb);
- return (retval);
- }
- #else
- /* Allocate block of 'nb' bytes */
- void *
- malloc(nb)
- unsigned nb;
- {
- return mallocw(nb);
- }
- #endif
-
- /* Allocate block of 'nb' bytes */
- static void *
- _malloc(nb)
- unsigned nb;
- {
- register HEADER *p, *q;
- register unsigned nu;
- int i;
-
- if(nb == 0)
- return NULL;
-
- /* Record the size of this request */
- if((i = log2((int16) nb)) >= 0)
- Sizes[i]++;
-
- #ifndef Kelvdebug
- /* Round up to full block, then add one for header */
-
- nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2; /* force allocated memory */
- nu &= 0xfffffffeL; /* to be on offset 0x0008 */
- #else
- /* Round up to full block, then add one for header and one for debug */
-
- nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4; /* force allocated memory */
- nu &= 0xfffffffeL; /* to be on offset 0x0008 */
- #endif
-
- if ((q = Allocp) == NULLHDR){
- Base.ptr = Allocp = q = &Base;
- Base.size = 1;
- }
-
- for (p = q->ptr; ; q = p, p = p->ptr){
- if (p->size >= nu){
- /* This chunk is at least as large as we need */
- if (p->size <= nu + 1){
- /* This is either a perfect fit (size == nu)
- * or the free chunk is just one unit larger.
- * In either case, alloc the whole thing,
- * because there's no point in keeping a free
- * block only large enough to hold the header.
- */
- q->ptr = p->ptr;
- } else {
- /* Carve out piece from end of entry */
- p->size -= nu;
- p += p->size;
- p->size = nu;
- }
- p->ptr = p; /* for auditing */
- #ifdef Kelvdebug
- p->l[(p->size * 2) - 2] = (long)p; /* debug */
- p->l[(p->size * 2) - 1] = MARKER; /* debug */
- #endif
- Allocs++;
- Availmem -= p->size;
- p++;
- /* On the brain-damaged Intel CPUs in
- * "large data" model, make sure the offset field
- * in the pointer we return isn't null.
- * The Turbo C compiler and certain
- * library functions like strrchr() assume this.
- */
- if(FP_OFF(p) == 0) /* Return denormalized but equivalent pointer */
- return (void *)(p - 1); /*lint !e413 */
-
- return (void *)p;
- }
- if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
- Memfail++;
- return NULL;
- }
- }
- }
- /* Get more memory from the system and put it on the heap */
- static HEADER *
- morecore(nu)
- unsigned nu;
- {
- void *cp;
- HEADER *up;
- unsigned size;
- void *sbrk(int); /***/
-
- Morecores++;
- size = nu * ABLKSIZE;
- /* First try to expand our main memory block */
- if((int)(cp = (void *)sbrk((int) size)) != -1){
- up = (HEADER *)cp;
- up->size = nu;
- up->ptr = up; /* satisfy audit */
- free(up + 1);
- Heapsize += size;
- Frees--; /* Nullify increment inside free() */
- return Allocp;
- }
- return NULL;
- }
-
-
- /* Put memory block back on heap */
- void
- free(blk)
- const void *blk;
- {
- register HEADER *p, *q;
- unsigned short *ptr;
-
- if(blk == NULL)
- return; /* Required by ANSI */
- p = (HEADER *)blk - 1;
- /* Audit check */
- if(p->ptr != p){
- ptr = (unsigned short *)&blk;
- tprintf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
- (void) fflush(stdout);
- Invalid++;
- log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
- (void) logstat();
- return;
- }
- #ifdef Kelvdebug
- if(p->l[(p->size * 2) - 2] != (long)p || p->l[(p->size * 2) - 1] != MARKER){
- ptr = (unsigned short *)&blk;
- tprintf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
- fflush(stdout);
- Overuse++;
- log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
- (void) logstat();
- return;
- }
- #endif
- Availmem += p->size;
- /* Search the free list looking for the right place to insert */
- for(q = Allocp; !(p > q && p < q->ptr); q = q->ptr){
- /* Highest address on circular list? */
- if(q >= q->ptr && (p > q || p < q->ptr))
- break;
- }
- if(p + p->size == q->ptr){
- /* Combine with front of this entry */
- p->size += q->ptr->size;
- p->ptr = q->ptr->ptr;
- } else {
- /* Link to front of this entry */
- p->ptr = q->ptr;
- }
- if(q + q->size == p){
- /* Combine with end of this entry */
- q->size += p->size;
- q->ptr = p->ptr;
- } else {
- /* Link to end of this entry */
- q->ptr = p;
- }
-
- Frees++;
- if(Memwait != 0)
- (void) ksignal(&Memwait,0);
- }
-
- #ifdef notdef /* Not presently used */
- /* Move existing block to new area */
- void *
- realloc(area,size)
- void *area;
- unsigned size;
- {
- unsigned osize;
- HEADER *hp;
- char *cp;
-
- hp = ((HEADER *)area) - 1;
- osize = (hp->size -1) * ABLKSIZE;
-
- free(area); /* Hopefully you have your interrupts off , Phil. */
- if((cp = _malloc(size)) != NULL && cp != area)
- memcpy((char *)cp,(char *)area,size>osize? osize : size);
- return cp;
- }
- /* Allocate block of cleared memory */
- void *
- calloc(nelem,size)
- unsigned nelem; /* Number of elements */
- unsigned size; /* Size of each element */
- {
- register unsigned i;
- register char *cp;
-
- i = nelem * size;
- if((cp = _malloc(i)) != NULL)
- memset(cp,0,i);
- return cp;
- }
- #endif
- /* Version of malloc() that waits if necessary for memory to become available */
- void *
- mallocw(nb)
- unsigned nb;
- {
- register void *p;
-
- while((p = _malloc(nb)) == NULL){
- Memwait++;
- kwait(&Memwait);
- Memwait--;
- }
- return p;
- }
- /* Version of calloc that waits if necessary for memory to become available */
- void *
- callocw(nelem,size)
- unsigned nelem; /* Number of elements */
- unsigned size; /* Size of each element */
- {
- register unsigned i;
- register char *cp;
-
- i = nelem * size;
- cp = mallocw(i);
- memset(cp,0,i);
- return cp;
- }
- /* Return available memory on our heap plus available system memory */
- static unsigned long
- availmem()
- {
- void *p;
-
- if(Availmem*ABLKSIZE >= (uint32) Memthresh)
- return 0; /* We're clearly OK */
-
- /* There's not enough on the heap; try calling malloc to see if
- * it can get more from the system
- */
- if((p = malloc((int16) Memthresh)) != NULL){
- free(p);
- return 0; /* Okay */
- }
- if((p = malloc((int16)(Memthresh/2))) != NULL){
- free(p);
- return 1; /* Yellow alert */
- }
- return 2; /* Red alert */
- }
-
- /* Log heap stats */
- static int
- logstat()
- {
- if(Memdebug) {
- log (-1, "Memory status :");
- log (-1, HeapSizeStr, Heapsize, Availmem * ABLKSIZE, \
- 100L * Availmem * ABLKSIZE / Heapsize, Morecores);
- log (-1, AllocStr, Allocs, Frees, Allocs - Frees, Memfail, Invalid
- #ifdef Kelvdebug
- , Overuse
- #endif
- );
- log (-1, GarbageStr, Yellows, Reds);
- log (-1, ThreshStr, Memthresh);
- }
- return 0;
- }
-
- void
- mbmemory (void)
- {
- tputs ("tnos: ");
- tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
- 100L*Availmem*ABLKSIZE/Heapsize,Morecores);
- tputc ('\n');
- }
-
-
-
- static void
- dpmistat (void)
- {
- _go32_dpmi_meminfo info;
- __dpmi_version_ret vers;
- int needcomma = 0;
- unsigned long pagesize;
-
- (void) __dpmi_get_version (&vers);
- tprintf ("\ndpmi: version %d.%d - ", vers.major, vers.minor);
- tprintf ("%-d bit host, %s mode, virtual memory %ssupported\n",
- (vers.flags & 1) ? 32 : 16, (vers.flags & 2) ? "real" : "V86",
- (vers.flags & 4) ? "" : "not ");
- if (__dpmi_get_page_size (&pagesize) != 0)
- pagesize = 0;
- if (_go32_dpmi_get_free_memory_information (&info) == 0) {
- tprintf (" avail mem %lu", info.available_memory);
- if (info.linear_space != (unsigned long) -1)
- tprintf (", linear mem %lu", (pagesize) ? info.linear_space * pagesize : info.linear_space);
- if (info.free_linear_space != (unsigned long) -1)
- tprintf (", free linear mem %lu", (pagesize) ? info.free_linear_space * pagesize : info.free_linear_space);
- tputc ('\n');
- if (pagesize) {
- tprintf (" page size %lu", pagesize);
- needcomma = 1;
- }
- if (info.total_physical_pages != (unsigned long) -1) {
- tprintf ("%sphy pages %lu", (needcomma) ? ", " : " ", info.total_physical_pages);
- needcomma = 1;
- }
- if (info.available_physical_pages != (unsigned long) -1) {
- tprintf ("%savail phy pages %lu", (needcomma) ? ", " : " ", info.available_physical_pages);
- needcomma = 1;
- }
- if (needcomma)
- tputc ('\n');
- needcomma = 0;
- if (info.available_pages != (unsigned long) -1) {
- tprintf (" avail pages %lu", info.available_pages);
- needcomma = 1;
- }
- if (info.available_lockable_pages != (unsigned long) -1) {
- tprintf ("%savail lockable pages %lu", (needcomma) ? ", " : " ", info.available_lockable_pages);
- needcomma = 1;
- }
- if (info.unlocked_pages != (unsigned long) -1) {
- tprintf ("%savail unlock pages %lu", (needcomma) ? ", " : " ", info.unlocked_pages);
- needcomma = 1;
- }
- if (needcomma)
- tputc ('\n');
- }
- }
-
-
-
- /* Print heap stats */
- int
- domemstat(argc,argv,envp)
- int argc;
- char *argv[];
- void *envp;
- {
- mbmemory ();
- tputs (" ");
- tprintf (AllocStr, Allocs, Frees, Allocs - Frees, Memfail, Invalid
- #ifdef Kelvdebug
- , Overuse
- #endif
- );
- tputc ('\n');
- tputs (" ");
- tprintf (GarbageStr, Yellows, Reds);
- dpmistat ();
- return 0;
- }
-
- /* Print heap free list */
- static int
- dofreelist(argc,argv,envp)
- int argc;
- char *argv[];
- void *envp;
- {
- HEADER *p;
- int i = 0;
-
- for(p = Base.ptr;p != (HEADER *)&Base;p = p->ptr){
- tprintf("%4.4x %6lu", p, p->size * ABLKSIZE);
- if(++i == 5){
- i = 0;
- if(tputc('\n') == EOF)
- return 0;
- } else
- (void) tputs(" | ");
- }
- if(i != 0)
- tputc('\n');
- return 0;
- }
- static int
- dosizes(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int i;
-
- for (i = 0; i <= 12; i += 4) {
- tprintf ("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
- 1<<i, Sizes[i], 2<<i,Sizes[i+1],
- 4<<i, Sizes[i+2], 8<<i,Sizes[i+3]);
- }
- return 0;
- }
- int
- domem(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return subcmd(Memcmds,argc,argv,p);
- }
-
- static int
- dothresh(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
- }
-
- static int
- dogcollect(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- void (**fp)(int);
-
- Yellows++;
- for(fp = Gcollect;*fp != NULL;fp++)
- (**fp)(0);
- (void) tputs ("Garbage collection forced at Yellow level!\n");
- return 0;
- }
-
-
- void
- gcollect(i,v1,v2)
- int i; /* Args not used */
- char *v1;
- void *v2;
- {
- void (**fp)(int);
- int red = 0;
-
- server_disconnect_io ();
- for ( ; ; ) {
- kpause (1000);
- switch(availmem()) {
- case 0:
- continue; /* All is well */
- case 1:
- red = 0;
- Yellows++;
- break;
- case 2:
- red = 1;
- Reds++;
- break;
- default:
- break;
- }
- for(fp = Gcollect;*fp != NULL;fp++)
- (**fp)(red);
- }
- }
-
- static int
- domemdebug(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
- }
-
- #endif /* !UNIX */
-